/*******************************************************************
*
*    DESCRIPTION:
*
*    AUTHOR:LiuHui
*
*    HISTORY:
*
*    DATE:1/22/2007
*
*******************************************************************/
/** include files **/
#include <config.h>
#include <debug.h>
#include <header.h>
#include <gui.h>
#include <language.h>
#include "xml_util.h"
#include "md5.h"
/** local definitions **/

/* default settings */

/** external functions **/

/** external data **/
/** internal functions **/
static xmlNodePtr xml_get_location(xmlDocPtr input, const xmlChar *path);
static void create_default_config_file(void);
static int is_program_exist(const xmlChar *path);
static int is_allow_existent_program(const xmlChar *path);
static void allow_existent_program(const xmlChar *path);
static void deny_existent_program(const xmlChar *path);
static void add_program_entry(xmlChar *path, xmlChar *is_allow);
static int get_program_counter(void);
static void save_config_file(void);
static int is_program_unmodified(const char * path);
static int is_user_defined_rule_exist(char *desc);
static int get_user_defined_rules_counter();
static struct list_head *get_user_defined_rules_list();
static void free_user_defined_rules_list(struct list_head *item_head);
/** public data **/
/** private data **/
static xmlDocPtr conf_xml = NULL;
/** public functions **/
/*
 *Function Name:init_conf_xml
 *
 *Parameters:
 *
 *Description:Initialize the configure xmlDoc.
 *
 *Returns:void
 *
 */
void init_conf_xml(void)
{
  conf_xml = xmlParseFile(COOLNET_CONFIG_FILE);
  if (NULL == conf_xml)
  {
    __ERROR_MSG("Can't open configure file:%s,use deault configure file.\n",
                COOLNET_CONFIG_FILE);
    /*Create default configure file*/
    create_default_config_file();
  }
#ifdef _DEBUG
  xmlDocDump(stdout, conf_xml);
#endif
}

/*
 *Function Name:is_first_time_start
 *
 *Parameters:void
 *
 *Description:
 *When startup coolnet, we need to check if the coolnet is first time to start.
 *We read the configure file to do this
 *
 *Returns:
 *1 -- is first time to start
 *0 -- is not first time to start
 */
int is_first_time_start (void)
{
  int ret = 0;
  xmlNodePtr node_ptr = NULL;
  xmlChar *value = NULL;
  node_ptr = xml_get_location(conf_xml, PATH(IS_FIRST_TIME_ELEM));
  value = xmlNodeGetContent(node_ptr);
  if (NULL == value)
  {
    __ERROR_MSG("Can't get the content from isfirsttimevalue node\n");
    ret = 0;
    goto out;
  }
  if (xmlStrcmp(value, (const xmlChar *)YES_VALUE) == 0)
  {
    __XML_DEBUG("Coolnet is the first time to start\n");
    ret = 1;
    goto out;
  }
  out:
  if (value != NULL)
  {
    xmlFree(value);
  }
  return ret;
}
/*
 *Function Name:set_program_have_started
 *
 *Parameters:void
 *
 *Description:After first time start, set program have started
 *
 *Returns:void
 *
 */
void set_program_have_started(void)
{
  xmlNodePtr node_ptr = NULL;
  node_ptr = xml_get_location(conf_xml, PATH(IS_FIRST_TIME_ELEM));
  xmlNodeSetContent(node_ptr, (const xmlChar *)NO_VALUE);
  save_config_file();
}

/*
 *Function Name:xml_updatemd5_program
 *
 *Parameters:
 *
 *Description:
 *
 *Returns:
 *
 */
int xml_updatemd5_program(xmlChar * path)
{
  int ret = _SUCCESS;
  xmlNodePtr item=NULL;
  char requry_path[_POSIX_PATH_MAX+256]={0};
  char md5sum_now[MD5SUM_LEN+1]={0};


  if (NULL == path)
  {
    __ERROR_MSG("The path of service can't be NULL\n");
    return _FAILED;
  }
  if (!is_program_exist(path))
  {
    __ERROR_MSG("The service doesn't exist.\n");
    return _FAILED;
  }

  sprintf(requry_path,"//%s[normalize-space(@path)='%s']",ITEM_ELEM,(char *)path);
  item=xml_get_location(conf_xml,(const xmlChar *)requry_path);
  md_file((const char *)path,(unsigned char *)md5sum_now);

  xmlSetProp(item, (const xmlChar *)MD5DIGEST_ATTR, (const xmlChar *)md5sum_now);
  save_config_file();

  __XML_DEBUG("Change the current program's MD5 digest to \n%s\n",md5sum_now);

  return ret;

}
/*
 *Function Name:xml_allow_program
 *
 *Parameters:
 *
 *Description:
 *If service entry existent in conf_xml, set the allow prop
 *If not append the entry
 *
 *Returns:_FAILED or _SUCCESS
 *
 */
int xml_allow_program(xmlChar *path)
{
  int ret = _SUCCESS;
  if (NULL == path)
  {
    __ERROR_MSG("The path of service can't be NULL\n");
    return _FAILED;
  }
  /*check if service is exist*/
  if (is_program_exist(path))
  {
    if (is_allow_existent_program(path))
    {
      __XML_DEBUG("The program was already allowed\n");
      ret = _FAILED;
      goto out;
    }
    else
    {
      allow_existent_program(path);
    }
  }
  else
  {
    add_program_entry(path, (xmlChar *)YES_VALUE);
  }
  out:
  return ret;
}

/*
 *Function Name:xml_deny_program
 *
 *Parameters:
 *
 *Description:
 *If service entry existent in conf_xml, set the allow prop
 *If not append the entry
 *
 *Returns:_FAILED or _SUCCESS
 *
 */
int xml_deny_program(xmlChar *path)
{
  int ret = _SUCCESS;
  if (NULL == path)
  {
    __ERROR_MSG("The path of service can't be NULL\n");
    return _FAILED;
  }
  /*check if service is exist*/
  if (is_program_exist(path))
  {
    if (!is_allow_existent_program(path))
    {
      __XML_DEBUG("The program was already denyed\n");
      ret = _FAILED;
      goto out;
    }
    else
    {
      deny_existent_program(path);
    }
  }
  else
  {
    add_program_entry(path, (xmlChar *)NO_VALUE);
  }
  out:
  return ret;
}
void xml_del_program_item(xmlChar *path)
{
  int counter = 0;
  char item_counter[4] = {0};
  xmlChar *temp_counter = NULL;
  xmlNodePtr parent = NULL;
  xmlNodePtr item = NULL;
  xmlChar *temp_path = NULL;
  if (!is_program_exist(path))
  {
    __ERROR_MSG("Program %s not exist\n", path);
    return;
  }
  parent = xml_get_location(conf_xml, PATH(PROGRAM_ELEM));
  item = parent->xmlChildrenNode;
  while (item != NULL)
  {
    temp_path = xmlGetProp(item, (const xmlChar *)PATH_ATTR);
    if (xmlStrcmp(temp_path, path) == 0)
    {
      xmlUnlinkNode(item);
      xmlFreeNode(item);
      /*reset service counter*/
      temp_counter = xmlGetProp(parent, (const xmlChar *)COUNTER_ATTR);
      counter = atoi((const char *)temp_counter);
      counter --;
      sprintf(item_counter, "%d", counter);
      xmlSetProp(parent, (const xmlChar *)COUNTER_ATTR, (const xmlChar *)item_counter);
      save_config_file();

      if (temp_path != NULL)
      {
        xmlFree(temp_path);
        temp_path = NULL;
      }
      if (temp_counter != NULL)
      {
        xmlFree(temp_counter);
        temp_counter = NULL;
      }

      break;
    }
    if (temp_path != NULL)
    {
      xmlFree(temp_path);
      temp_path = NULL;
    }
    item = item->next;
  }
  save_config_file();
}

/*
 *Function Name:xml_is_allow_program
 *
 *Parameters:
 *
 *Description:
 *
 *Returns: 
 *1 -- allow program, 0 -- deny program
 *-1 -- program not exist, -2 -- in allow list but with a error MD5 sum
 *
 */
int xml_is_allow_program(xmlChar *path)
{
  int ret = -1;
  struct program_item *item = NULL;
  struct list_head *head = NULL;
  struct list_head *p = NULL;
  head = get_program_list();
  list_for_each(p, head)
  {
    item = list_entry(p, struct program_item, list);
    if (strcmp((const char *)path, item->path) == 0)
    {
      if (item->allow)
      {
        //zyh add
        if (is_program_unmodified((const char*)path)==0)
        {
          ret=-2;
          goto out;
        }
        ret = 1;
        goto out;
      }
      else
      {
        ret = 0;
        goto out;
      }
    }
  }
  out:
  free_program_list(head);
  return ret;
}

void xml_add_user_defined_rules(xmlChar *rules_desc,
                                int proto,
                                int localport_from,
                                int localport_to,
                                int remoteport_from,
                                int remoteport_to,
                                int action)
{
  int item_counter = 0;
  xmlNodePtr parent_node = NULL;
  xmlNodePtr item_node = NULL;
  char counter[4] = {0};
  char lpf[8] = {0};
  char lpt[8] = {0};
  char rpf[8] = {0};
  char rpt[8] = {0};
  if (is_user_defined_rule_exist((char *)rules_desc))
  {
    popup_error_dialog(NULL, GTK_MESSAGE_ERROR, TEXT_RULES_ALREADY_EXIT);
    return;
  }

  item_counter = get_user_defined_rules_counter();
  item_counter ++;

  sprintf(counter, "%d", item_counter);
  parent_node = xml_get_location(conf_xml, PATH(USER_DEFINED_ELEM));
  /*reset counter*/
  xmlSetProp(parent_node, (const xmlChar *)COUNTER_ATTR, (xmlChar *)counter);

  item_node = xmlNewChild(parent_node, NULL, (const xmlChar *)ITEM_ELEM, NULL);
  /*add prop*/
  xmlNewProp(item_node, (const xmlChar *)DESC_ATTR, rules_desc);
  xmlNewProp(item_node, (const xmlChar *)PROTO_ATTR,
             IPPROTO_TCP == proto ? (const xmlChar *)TCP_VALUE : (const xmlChar *)UDP_VALUE);
  xmlNewProp(item_node, (const xmlChar *)ACTION_ATTR,
             NF_ACCEPT == action ? (const xmlChar *)ACCEPT_VALUE : (const xmlChar *)DROP_VALUE);
  sprintf(lpf, "%d", localport_from);
  xmlNewProp(item_node, (const xmlChar *)LPF_ATTR, (const xmlChar *)lpf);
  sprintf(lpt, "%d", localport_to);
  xmlNewProp(item_node, (const xmlChar *)LPT_ATTR, (const xmlChar *)lpt);
  sprintf(rpf, "%d", remoteport_from);
  xmlNewProp(item_node, (const xmlChar *)RPF_ATTR, (const xmlChar *)rpf);
  sprintf(rpt, "%d", remoteport_to);
  xmlNewProp(item_node, (const xmlChar *)RPT_ATTR, (const xmlChar *)rpt);
  xmlNewProp(item_node, (const xmlChar *)STATUS_ATTR, (const xmlChar *)YES_VALUE);
  save_config_file();
}

struct list_head *get_program_list(void)
{

  int counter = 0;
  xmlNodePtr parent_node = NULL;
  xmlNodePtr item_node = NULL;

  struct program_item *item = NULL;
  xmlChar *temp_path = NULL;
  xmlChar *temp_allow = NULL;

  struct list_head *head = malloc(sizeof(struct list_head));
  if (NULL == head)
  {
    __ERROR_MSG("Error when alloc memory\n");
    goto out;
  }
  memset(head, 0, sizeof(struct list_head));
  INIT_LIST_HEAD(head);

  counter = get_program_counter();

  if (0 == counter)
  {
    goto out;
  }

  /*get service list*/
  parent_node = xml_get_location(conf_xml, PATH(PROGRAM_ELEM));
  item_node = parent_node->xmlChildrenNode;
  while (item_node != NULL)
  {
    item = malloc(sizeof(struct program_item));
    if (NULL == item)
    {
      __ERROR_MSG("Error when alloc memory\n");
      goto _next;
    }
    memset(item, 0, sizeof(struct program_item));
    temp_path = xmlGetProp(item_node, (const xmlChar *)PATH_ATTR);
    temp_allow = xmlGetProp(item_node, (const xmlChar *)ALLOW_ATTR);

    /*
    *FIXME:For some unkonw reason, temp_path and temp_allow sometimes is NULL.
    *To avoid this,i add the following code to skip the NULL node.
    */
    if (NULL == temp_path || NULL == temp_allow)
    {
      goto _next;
    }

    item->path = (char *)temp_path;
    if (xmlStrcmp(temp_allow, (const xmlChar *)YES_VALUE) == 0)
    {
      item->allow = 1;
    }
    else if (xmlStrcmp(temp_allow, (const xmlChar *)NO_VALUE) == 0)
    {
      item->allow = 0;
    }

    list_add(&item->list, head);
    _next:
    if (temp_allow != NULL)
    {
      xmlFree(temp_allow);

    }
    item_node = item_node->next;
    item = NULL;
    temp_allow = NULL;
    temp_path = NULL;
  }
  out:
  return head;
}
void free_program_list(struct list_head *item_head)
{
  struct list_head *p = NULL;
  struct list_head *temp = NULL;
  struct program_item *item = NULL;

  if (list_empty(item_head))
  {
    free(item_head);
    return;
  }

  p = item_head->next;
  while (p != item_head)
  {
    item = list_entry(p, struct program_item, list);
    temp = p;
    p = p->next;
    list_del(temp);
    free(item->path);
    free(item);
  }

  free(item_head);
}
void xml_delete_user_defined_rules(xmlChar *rule_desc)
{
  int counter = 0;
  char item_counter[4] = {0};
  xmlChar *temp_counter = NULL;
  xmlNodePtr parent = NULL;
  xmlNodePtr item = NULL;
  xmlChar *temp_desc = NULL;
  if (!is_user_defined_rule_exist((char *)rule_desc))
  {
    __ERROR_MSG("User-defined rules %s not exist\n", rule_desc);
    return;
  }
  parent = xml_get_location(conf_xml, PATH(USER_DEFINED_ELEM));
  item = parent->xmlChildrenNode;
  while (item != NULL)
  {
    temp_desc = xmlGetProp(item, (const xmlChar *)DESC_ATTR);
    if (xmlStrcmp(temp_desc, rule_desc) == 0)
    {
      xmlUnlinkNode(item);
      xmlFreeNode(item);
      /*reset service counter*/
      temp_counter = xmlGetProp(parent, (const xmlChar *)COUNTER_ATTR);
      counter = atoi((const char *)temp_counter);
      counter --;
      sprintf(item_counter, "%d", counter);
      xmlSetProp(parent, (const xmlChar *)COUNTER_ATTR, (const xmlChar *)item_counter);
      save_config_file();

      if (temp_desc != NULL)
      {
        xmlFree(temp_desc);
        temp_desc = NULL;
      }
      if (temp_counter != NULL)
      {
        xmlFree(temp_counter);
        temp_counter = NULL;
      }

      break;
    }
    if (temp_desc != NULL)
    {
      xmlFree(temp_desc);
      temp_desc = NULL;
    }
    item = item->next;
  }
  save_config_file();
}
void xml_set_user_defined_rules_status(xmlChar *rules_desc, xmlChar *active)
{
  xmlNodePtr node_p=NULL;
  char requry_path[_POSIX_PATH_MAX+256]={0};

  sprintf(requry_path,"//%s[normalize-space(@%s)='%s']",
          ITEM_ELEM,
          DESC_ATTR,
          rules_desc); 
  /*find node by rules_desc*/
  node_p=xml_get_location(conf_xml, (const xmlChar *)requry_path);
  if (NULL == node_p)
  {
    __ERROR_MSG("Can't find user-define rule\n");
    return;
  }
  /*set rules prop*/
  xmlSetProp(node_p, (const xmlChar *)DESC_ATTR, active);
  save_config_file();
}
static void create_default_config_file(void)
{
  xmlNodePtr root = NULL;
  xmlNodePtr temp_node = NULL;
  /*create root element*/
  conf_xml = xmlNewDoc((const xmlChar *)"1.0");
  root = xmlNewNode(NULL, (const xmlChar *)CONF_ELEM);
  xmlDocSetRootElement(conf_xml, root);
  /*create second level child*/
  temp_node = xmlNewChild(root, NULL, (const xmlChar *)PROGRAM_ELEM, NULL);/*program*/
  xmlNewProp(temp_node, (const xmlChar *)COUNTER_ATTR, (const xmlChar *)DEFAULT_COUNTER_VALUE);
  temp_node = xmlNewChild(root, NULL, (const xmlChar *)USER_DEFINED_ELEM, NULL);/*user-defined*/
  xmlNewProp(temp_node, (const xmlChar *)COUNTER_ATTR, (const xmlChar *)DEFAULT_COUNTER_VALUE);
  temp_node = xmlNewChild(root, NULL, (const xmlChar *)MISC_ELEM, NULL);/*misc*/
  /*create third level child*/
  xmlNewChild(temp_node, NULL, (const xmlChar *)IS_FIRST_TIME_ELEM, (const xmlChar *)YES_VALUE);
  xmlNewChild(temp_node, NULL, (const xmlChar *)START_WITH_BOOT_ELEM, (const xmlChar *)YES_VALUE);
  /*save config file*/
  save_config_file();
}
static xmlNodePtr xml_get_location(xmlDocPtr input, const xmlChar *path)
{
  xmlNodePtr cur_tree_node = NULL;
  xmlXPathContextPtr ctx = NULL;
  xmlXPathObjectPtr xpath = NULL;

  if (NULL == path)
    return NULL;

  xmlXPathInit ();
  ctx = xmlXPathNewContext(input);

  if ((xpath = xmlXPathEvalExpression((xmlChar *) path, ctx)) == NULL)
    goto out;

  if (xpath->nodesetval == NULL)
    goto out;

  if (xpath->nodesetval->nodeTab == NULL)
    goto out;

  cur_tree_node = xpath->nodesetval->nodeTab[0];

  out:
  if (xpath != NULL)
    xmlXPathFreeObject(xpath);
  if (ctx != NULL)
    xmlXPathFreeContext(ctx);

  return cur_tree_node;
}
static int is_program_exist(const xmlChar *path)
{
  int ret = 0;
  struct list_head *item_head = NULL;
  struct list_head *p = NULL;
  struct program_item *item = NULL;

  if (NULL == path)
  {
    __ERROR_MSG("The path of service can't be NULL\n");
    return -1;
  }

  item_head = get_program_list();

  list_for_each(p, item_head)
  {
    item = list_entry(p, struct program_item, list);

    if ((xmlStrcmp((const xmlChar *)path, (const xmlChar *)item->path) == 0))
    {
      ret = 1;
      goto out;
    }
  }
  out:
  free_program_list(item_head);
  return ret;
}
static int is_allow_existent_program(const xmlChar *path)
{
  struct list_head *item_head = NULL;
  struct list_head *p = NULL;
  struct program_item *item = NULL;
  int ret = 0;
  item_head = get_program_list();
  list_for_each(p, item_head){
    item = list_entry(p, struct program_item, list);
    if (0 == strcmp(item->path, (char *)path) && 1 == item->allow)
    {
      ret = 1;
      goto out;
    }
  }
  out:
  free_program_list(item_head);
  return ret;
}
static void allow_existent_program(const xmlChar *path)
{
  xmlChar *temp_path = NULL;
  xmlNodePtr parent = NULL;
  xmlNodePtr item_node = NULL;
  parent = xml_get_location(conf_xml, PATH(PROGRAM_ELEM));
  item_node = parent->xmlChildrenNode;
  while (item_node != NULL)
  {
    temp_path = xmlGetProp(item_node, (const xmlChar *)PATH_ATTR);

    if (xmlStrcmp(path, temp_path) == 0)
    {
      xmlSetProp(item_node, (const xmlChar *)ALLOW_ATTR, (const xmlChar *)YES_VALUE);
      if (temp_path != NULL)
      {
        xmlFree(temp_path);
        temp_path = NULL;
      }
      break;
    }
    if (temp_path != NULL)
    {
      xmlFree(temp_path);
      temp_path = NULL;
    }
    item_node = item_node->next;
  }
  save_config_file();
}

static void deny_existent_program(const xmlChar *path)
{
  xmlChar *temp_path = NULL;
  xmlNodePtr parent = NULL;
  xmlNodePtr item_node = NULL;
  parent = xml_get_location(conf_xml, PATH(PROGRAM_ELEM));
  item_node = parent->xmlChildrenNode;
  while (item_node != NULL)
  {
    temp_path = xmlGetProp(item_node, (const xmlChar *)PATH_ATTR);

    if (xmlStrcmp(path, temp_path) == 0)
    {
      xmlSetProp(item_node, (const xmlChar *)ALLOW_ATTR, (const xmlChar *)NO_VALUE);
      if (temp_path != NULL)
      {
        xmlFree(temp_path);
        temp_path = NULL;
      }
      break;
    }
    if (temp_path != NULL)
    {
      xmlFree(temp_path);
      temp_path = NULL;
    }
    item_node = item_node->next;
  }
  save_config_file();
}
static void add_program_entry(xmlChar *path, xmlChar  *is_allow)
{
  int item_counter = 0;
  xmlNodePtr parent_node = NULL;
  xmlNodePtr item_node = NULL;
  char counter[4]={0};
  char digest[MD5SUM_LEN+1]={0};

  md_file((char *)path, (unsigned char *)digest);

  item_counter = get_program_counter();
  item_counter ++;


  sprintf(counter, "%d", item_counter);
  parent_node = xml_get_location(conf_xml, PATH(PROGRAM_ELEM));
  /*reset counter*/
  xmlSetProp(parent_node, (const xmlChar *)COUNTER_ATTR, (xmlChar *)counter);

  item_node = xmlNewChild(parent_node, NULL, (const xmlChar *)ITEM_ELEM, NULL);

  xmlNewProp(item_node, (const xmlChar *)PATH_ATTR, path);
  xmlNewProp(item_node, (const xmlChar *)ALLOW_ATTR, is_allow);
  xmlNewProp(item_node, (const xmlChar *)MD5DIGEST_ATTR, (const xmlChar *)digest);

  save_config_file();
}



static int get_program_counter()
{
  int counter = 0;
  xmlChar *temp_counter = NULL;
  xmlNodePtr node = NULL;
  node = xml_get_location(conf_xml, PATH(PROGRAM_ELEM));
  temp_counter = xmlGetProp(node, (const xmlChar *)COUNTER_ATTR);
  counter = atoi((char *)temp_counter);
  if (temp_counter != NULL)
  {
    xmlFree(temp_counter);
  }
  return counter;
}
static void save_config_file()
{
#ifdef _XML_DEBUG
  xmlDocDump(stdout, conf_xml);
#endif
  xmlSaveFormatFile(COOLNET_CONFIG_FILE, conf_xml, 1);
}


/*
 *Function Name:is_program_unmodified
 *
 *Parameters:
 *
 *Description:
 *
 *Returns: 
 *0 -- program has been modified,
 *1 -- program is unmodified
 *
 */

static int is_program_unmodified(const char * path)
{
  char md5sum_now[MD5SUM_LEN+1]={0};

  xmlNodePtr node_p=NULL;
  xmlChar * md5digest_attr=NULL;
  char requry_path[_POSIX_PATH_MAX+256]={0};
  int ret=1;

  md_file(path,(unsigned char *)md5sum_now);

  sprintf(requry_path,"//%s[normalize-space(@path)='%s']",
          ITEM_ELEM,
          path); 
  node_p=xml_get_location(conf_xml,(const xmlChar *)requry_path);
  if (NULL==node_p)
  {
    __ERROR_MSG("I can't find xml node with %s\n",path);
    __ERROR_MSG("A internal error occured.\n");
    ret = 0;
    goto out;
  }

  md5digest_attr=xmlGetProp(node_p, (const xmlChar *)MD5DIGEST_ATTR);
  if (NULL==md5digest_attr) //If for some reason,it's absent.Recompute it
  {
    xmlNewProp(node_p, (const xmlChar *)MD5DIGEST_ATTR, (const xmlChar *)md5sum_now);
    save_config_file();
    goto out;
  }

  if (!xmlStrcmp((xmlChar *)md5sum_now,md5digest_attr))
    ret=1;//unmodified
  else
    ret=0;

  goto out;

  out:
  if (md5digest_attr)
  {
    xmlFree(md5digest_attr);
  }
  return ret;
}
static int is_user_defined_rule_exist(char *desc)
{
  struct list_head *head = NULL;
  struct list_head *p = NULL;
  struct user_defined_item *item = NULL;
  int ret = 0;
  head = get_user_defined_rules_list();
  list_for_each(p, head)
  {
    item = list_entry(p, struct user_defined_item, list);
    if (strcmp(desc, item->desc) == 0)
    {
      ret = 1;
      goto out;
    }
  }
  out:
  free_user_defined_rules_list(head);
  return ret;
}
static struct list_head *get_user_defined_rules_list()
{

  int counter = 0;
  xmlNodePtr parent_node = NULL;
  xmlNodePtr item_node = NULL;

  struct user_defined_item *item = NULL;
  xmlChar *temp_desc = NULL;
  xmlChar *temp_action = NULL;
  xmlChar *temp_proto = NULL;
  xmlChar *temp_lpf = NULL;
  xmlChar *temp_lpt = NULL;
  xmlChar *temp_rpf = NULL;
  xmlChar *temp_rpt = NULL;
  xmlChar *temp_status = NULL;

  struct list_head *head = malloc(sizeof(struct list_head));
  if (NULL == head)
  {
    __ERROR_MSG("Error when alloc memory\n");
    goto out;
  }
  memset(head, 0, sizeof(struct list_head));
  INIT_LIST_HEAD(head);

  counter = get_user_defined_rules_counter();

  if (0 == counter)
  {
    goto out;
  }

  /*get service list*/
  parent_node = xml_get_location(conf_xml, PATH(USER_DEFINED_ELEM));
  item_node = parent_node->xmlChildrenNode;
  while (item_node != NULL)
  {
    item = malloc(sizeof(struct user_defined_item));
    if (NULL == item)
    {
      __ERROR_MSG("Error when alloc memory\n");
      goto _next;
    }
    memset(item, 0, sizeof(struct user_defined_item));
    temp_desc = xmlGetProp(item_node, (const xmlChar *)DESC_ATTR);
    temp_proto = xmlGetProp(item_node, (const xmlChar *)PROTO_ATTR);
    temp_action = xmlGetProp(item_node, (const xmlChar *)ACTION_ATTR);
    temp_lpf = xmlGetProp(item_node, (const xmlChar *)LPF_ATTR);
    temp_lpt = xmlGetProp(item_node, (const xmlChar *)LPT_ATTR);
    temp_rpf = xmlGetProp(item_node, (const xmlChar *)RPF_ATTR);
    temp_rpt = xmlGetProp(item_node, (const xmlChar *)RPT_ATTR);
    temp_status = xmlGetProp(item_node, (const xmlChar *)STATUS_ATTR);

    /*FIXME:the same problem as get_program_list*/
    if (NULL == temp_desc || NULL == temp_proto ||
        NULL == temp_action || NULL ==  temp_lpf ||
        NULL == temp_lpt || NULL == temp_rpf ||
        NULL == temp_rpt || NULL == temp_status)
    {
      goto _next;
    }

    item->desc = (char *)temp_desc;

    if (0 == xmlStrcmp(temp_proto, (const xmlChar *)TCP_VALUE))
    {
      item->proto = IPPROTO_TCP;
    }
    else if (0 == xmlStrcmp(temp_proto, (const xmlChar *)UDP_VALUE))
    {
      item->proto = IPPROTO_UDP;
    }

    if (0 == xmlStrcmp(temp_action, (const xmlChar *)ACCEPT_VALUE))
    {
      item->action = NF_ACCEPT;
    }
    else if (0 == xmlStrcmp(temp_proto, (const xmlChar *)DROP_VALUE))
    {
      item->action = NF_DROP;
    }

    if (0 == xmlStrcmp(temp_status, (const xmlChar *)YES_VALUE))
    {
      item->status = 1;
    }
    else if (0 == xmlStrcmp(temp_proto, (const xmlChar *)NO_VALUE))
    {
      item->status = 0;
    }

    item->localport_from = atoi((char *)temp_lpf);
    item->localport_to = atoi((char *)temp_lpt);
    item->remoteport_from = atoi((char *)temp_rpf);
    item->remoteport_to = atoi((char *)temp_rpt);

    list_add(&item->list, head);

    _next:
    if (temp_action != NULL)
    {
      xmlFree(temp_action);
    }
    if (temp_proto != NULL)
    {
      xmlFree(temp_proto);
    }
    if (temp_lpf != NULL)
    {
      xmlFree(temp_lpf);
    }
    if (temp_lpt != NULL)
    {
      xmlFree(temp_lpt);
    }
    if (temp_rpf != NULL)
    {
      xmlFree(temp_rpf);
    }
    if (temp_rpt != NULL)
    {
      xmlFree(temp_rpt);
    }
    if (temp_status != NULL)
    {
      xmlFree(temp_status);
    }
    item_node = item_node->next;
    item = NULL;
    temp_desc = NULL;
    temp_action = NULL;
    temp_proto = NULL;
    temp_lpf = NULL;
    temp_lpt = NULL;
    temp_rpf = NULL;
    temp_rpt = NULL;
    temp_status = NULL;
  }
  out:
  return head;
}
static void free_user_defined_rules_list(struct list_head *item_head)
{
  struct list_head *p = NULL;
  struct list_head *temp = NULL;
  struct user_defined_item *item = NULL;

  if (list_empty(item_head))
  {
    free(item_head);
    return;
  }

  p = item_head->next;
  while (p != item_head)
  {
    item = list_entry(p, struct user_defined_item, list);
    temp = p;
    p = p->next;
    list_del(temp);
    free(item->desc);
    free(item);
  }

  free(item_head);
}
static int get_user_defined_rules_counter()
{
  int counter = 0;
  xmlChar *temp_counter = NULL;
  xmlNodePtr node = NULL;
  node = xml_get_location(conf_xml, PATH(USER_DEFINED_ELEM));
  temp_counter = xmlGetProp(node, (const xmlChar *)COUNTER_ATTR);
  counter = atoi((char *)temp_counter);
  if (temp_counter != NULL)
  {
    xmlFree(temp_counter);
  }
  return counter;
}








